﻿using System;
using System.Text;
using System.Net;
using System.IO;
using InfoSvc.Data;
using InfoSvc.Data.WPP;
using Newtonsoft.Json;
using System.Windows;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

namespace WPP_Console
{
    public static class ServiceClient
    {
        /// <summary>
        /// The base address of the IIS server.
        /// </summary>
        private static string ServiceAddress = "";
        //private static string gsuServiceAddress = "http://localhost:46202/";

        private static string username = "";
        private static string password = "";

        public static string Username
        {
            get { return username; }
            set { username = value; }
        }

        public static string Password
        {
            get { return password; }
            set { password = value; }
        }

        #region Method Wrappers

        /// <summary>
        /// Wrapper for calling the GetOrders service method.
        /// </summary>
        /// <param name="oq">The OrderQuery will be used to filter results from the database.</param>
        /// <returns>
        /// The array of Orders returned matches the search criteria provided to the methdods. 
        /// Index 0 contains A response from the service detailing the sucecess of the call.
        /// </returns>
        public static Order[] GetOrders(OrderQuery oq)
        {
            string json = JsonConvert.SerializeObject(oq);
            string result = "";
            try
            {
                result = "[{\"GetResponse\":null,\"InvokeResponse\":null,\"Cancelled\":false,\"Cleared\":false,\"Complete\":true,\"OrderBillingName\":\"First Last\",\"OrderCompleteDate\":\"\\/Date(1357651036000)\\/\",\"OrderCreationDate\":\"\\/Date(1351555200000)\\/\",\"OrderID\":1,\"OrderNumber\":\"38625\",\"OrderProcessDate\":\"\\/Date(1342224000000)\\/\",\"OrderShippingName\":\"First Last\",\"OrderTransactionDate\":\"\\/Date(1351728000000)\\/\",\"Packages\":[{\"GetResponse\":null,\"InvokeResponse\":null,\"Cancelled\":false,\"Complete\":true,\"CustomerIdentifier\":\"HI_fe32423444\",\"MultiBox\":false,\"OrderItems\":[{\"GetResponse\":null,\"InvokeResponse\":null,\"ItemCustomerNotes\":\"\",\"ItemDescription\":\"Test Item\",\"ItemNumber\":\"1\",\"ItemPossku\":\"3403084752\",\"ItemQuantity\":7,\"OrderItemID\":1}],\"PackageDateBoxed\":\"\\/Date(1349049600000)\\/\",\"PackageID\":1,\"PackageNumber\":\"43602\",\"PackagePickupDate\":\"\\/Date(1357651036000)\\/\",\"PackageStatus\":null}],\"Phone\":\"5555556247     \"},{\"GetResponse\":null,\"InvokeResponse\":null,\"Cancelled\":false,\"Cleared\":false,\"Complete\":false,\"OrderBillingName\":\"First Last\",\"OrderCompleteDate\":null,\"OrderCreationDate\":\"\\/Date(1357292460000)\\/\",\"OrderID\":2,\"OrderNumber\":\"123446204\",\"OrderProcessDate\":\"\\/Date(1345898100000)\\/\",\"OrderShippingName\":\"First Last\",\"OrderTransactionDate\":\"\\/Date(1345838820000)\\/\",\"Packages\":[{\"GetResponse\":null,\"InvokeResponse\":null,\"Cancelled\":false,\"Complete\":false,\"CustomerIdentifier\":null,\"MultiBox\":false,\"OrderItems\":[{\"GetResponse\":null,\"InvokeResponse\":null,\"ItemCustomerNotes\":\"\",\"ItemDescription\":\"CLASSNOTES-HUMN 2434-F12 new\",\"ItemNumber\":\"9781453402153\",\"ItemPossku\":\"9781453402153\",\"ItemQuantity\":1,\"OrderItemID\":2},{\"GetResponse\":null,\"InvokeResponse\":null,\"ItemCustomerNotes\":\"\",\"ItemDescription\":\"(U)WORLD MYTHOLOGY used\",\"ItemNumber\":\"9780195307528\",\"ItemPossku\":\"2900195307527\",\"ItemQuantity\":1,\"OrderItemID\":3},{\"GetResponse\":null,\"InvokeResponse\":null,\"ItemCustomerNotes\":\"\",\"ItemDescription\":\"(U)YOU MAY ASK YOURSELF used\",\"ItemNumber\":\"9780393935172\",\"ItemPossku\":\"2900393935171\",\"ItemQuantity\":1,\"OrderItemID\":4}],\"PackageDateBoxed\":\"\\/Date(1349049600000)\\/\",\"PackageID\":2,\"PackageNumber\":\"59110\",\"PackagePickupDate\":null,\"PackageStatus\":null}],\"Phone\":\"5555551357     \"},{\"GetResponse\":null,\"InvokeResponse\":null,\"Cancelled\":false,\"Cleared\":false,\"Complete\":false,\"OrderBillingName\":\"First Last\",\"OrderCompleteDate\":null,\"OrderCreationDate\":\"\\/Date(1357292460000)\\/\",\"OrderID\":3,\"OrderNumber\":\"123438212\",\"OrderProcessDate\":\"\\/Date(1345897620000)\\/\",\"OrderShippingName\":\"First Last\",\"OrderTransactionDate\":\"\\/Date(1345838820000)\\/\",\"Packages\":[{\"GetResponse\":null,\"InvokeResponse\":null,\"Cancelled\":false,\"Complete\":false,\"CustomerIdentifier\":null,\"MultiBox\":false,\"OrderItems\":[{\"GetResponse\":null,\"InvokeResponse\":null,\"ItemCustomerNotes\":\"\",\"ItemDescription\":\"i>clicker2 Item\",\"ItemNumber\":\"W11240\",\"ItemPossku\":\"1429280476\",\"ItemQuantity\":1,\"OrderItemID\":5}],\"PackageDateBoxed\":\"\\/Date(1345897620000)\\/\",\"PackageID\":3,\"PackageNumber\":\"59108\",\"PackagePickupDate\":null,\"PackageStatus\":null}],\"Phone\":\"5555555801     \"},{\"GetResponse\":null,\"InvokeResponse\":null,\"Cancelled\":false,\"Cleared\":false,\"Complete\":false,\"OrderBillingName\":\"First Last\",\"OrderCompleteDate\":null,\"OrderCreationDate\":\"\\/Date(1357292460000)\\/\",\"OrderID\":4,\"OrderNumber\":\"123435305\",\"OrderProcessDate\":\"\\/Date(1345893420000)\\/\",\"OrderShippingName\":\"First Last\",\"OrderTransactionDate\":\"\\/Date(1345841160000)\\/\",\"Packages\":[{\"GetResponse\":null,\"InvokeResponse\":null,\"Cancelled\":false,\"Complete\":false,\"CustomerIdentifier\":null,\"MultiBox\":false,\"OrderItems\":[{\"GetResponse\":null,\"InvokeResponse\":null,\"ItemCustomerNotes\":\"\",\"ItemDescription\":\"CHEM 1145 LAB MANUAL 11\\/12 new\",\"ItemNumber\":\"9781453401088\",\"ItemPossku\":\"9781453401088\",\"ItemQuantity\":1,\"OrderItemID\":6},{\"GetResponse\":null,\"InvokeResponse\":null,\"ItemCustomerNotes\":\"\",\"ItemDescription\":\"(U)LONE RANGER+TONTO FISTFIGHT IN HEAVEN used\",\"ItemNumber\":\"9780802141675\",\"ItemPossku\":\"2900802141674\",\"ItemQuantity\":1,\"OrderItemID\":7},{\"GetResponse\":null,\"InvokeResponse\":null,\"ItemCustomerNotes\":\"\",\"ItemDescription\":\"(U)TOURISTS OF HISTORY used\",\"ItemNumber\":\"9780822341222\",\"ItemPossku\":\"2900822341221\",\"ItemQuantity\":1,\"OrderItemID\":8}],\"PackageDateBoxed\":\"\\/Date(1345893420000)\\/\",\"PackageID\":4,\"PackageNumber\":\"59056\",\"PackagePickupDate\":null,\"PackageStatus\":null}],\"Phone\":\"5555553997     \"},{\"GetResponse\":null,\"InvokeResponse\":null,\"Cancelled\":false,\"Cleared\":false,\"Complete\":false,\"OrderBillingName\":\"First Last\",\"OrderCompleteDate\":null,\"OrderCreationDate\":\"\\/Date(1357292460000)\\/\",\"OrderID\":5,\"OrderNumber\":\"123419213\",\"OrderProcessDate\":\"\\/Date(1345893780000)\\/\",\"OrderShippingName\":\"First Last\",\"OrderTransactionDate\":\"\\/Date(1345841940000)\\/\",\"Packages\":[{\"GetResponse\":null,\"InvokeResponse\":null,\"Cancelled\":false,\"Complete\":false,\"CustomerIdentifier\":null,\"MultiBox\":false,\"OrderItems\":[{\"GetResponse\":null,\"InvokeResponse\":null,\"ItemCustomerNotes\":\"\",\"ItemDescription\":\"(U)WRITING TODAY,BRIEF ED. used\",\"ItemNumber\":\"9780205230402\",\"ItemPossku\":\"2900205230401\",\"ItemQuantity\":1,\"OrderItemID\":9}],\"PackageDateBoxed\":\"\\/Date(1345893780000)\\/\",\"PackageID\":5,\"PackageNumber\":\"59061\",\"PackagePickupDate\":null,\"PackageStatus\":null}],\"Phone\":\"5555550668     \"}]";
            }
            catch (Exception e)
            {
                MessageBox.Show(e.ToString());
            }
            Order[] o;
            try
            {
                return (Order[])JsonConvert.DeserializeObject(result, typeof(Order[]));
            }
            catch (ArgumentNullException e)
            {
                o = new Order[1];
                o[0] = new Order();
                o[0].GetResponse = new GetResponse();
                o[0].GetResponse.ErrorMessage = "Data returned was null.";
            }
            return o;
        }

        /// <summary>
        /// Wrapper for calling the UpdatePackage service method.
        /// </summary>
        /// <param name="p">Applies any changes made in p to the object state in the database.</param>
        /// <returns>A response from the service detailing the sucecess of the call.</returns>
        public static InvokeResponse UpdatePackage(Package p)
        {
            string result = CallPutService("wpp/package", JsonConvert.SerializeObject(p));
            return (InvokeResponse)JsonConvert.DeserializeObject(result, typeof(InvokeResponse));
        }

        /// <summary>
        /// Wrapper for calling the UpdateOrder service method.
        /// </summary>
        /// <param name="p">Applies any changes made in o to the object state in the database.</param>
        /// <returns>A response from the service detailing the sucecess of the call.</returns>
        public static InvokeResponse UpdateOrder(Order o)
        {
            string result = CallPutService("wpp/order", JsonConvert.SerializeObject(o));
            return (InvokeResponse)JsonConvert.DeserializeObject(result, typeof(InvokeResponse));        
        }

        /// <summary>
        /// Wrapper for calling the BatchClear method.
        /// </summary>
        /// <param name="dg">DateGroup having DateType of BATCH_CLEAR and a date range to mark as cleared.</param>
        /// <returns>A response from the service detailing the sucecess of the call.</returns>
        public static InvokeResponse BatchClear(DateGroup dg)
        {
            string result = CallPostService("wpp/clear", JsonConvert.SerializeObject(dg));
            return (InvokeResponse)JsonConvert.DeserializeObject(result, typeof(InvokeResponse));
        }

        #endregion

        #region Client Communication

        /// <summary>
        /// Retrieves data from the service via HTTP GET. GET must not affect the state of the database.
        /// </summary>
        /// <param name="url">The url of the service endpoint</param>
        /// <returns>The response from the service as a JSON string</returns>
        private static string CallGetService(string url)
        {
            url = ServiceAddress + url;
            // declare httpwebrequest with url defined above
            HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(url);
            webrequest.Method = "GET";
            webrequest.Credentials = new NetworkCredential(username, password);
            webrequest.ContentType = "application/x-www-form-urlencoded";

            // set up certificate trust
            ServicePointManager.ServerCertificateValidationCallback =
            new RemoteCertificateValidationCallback(
            delegate(object sender2, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
            {
                return true;
            });
            // declare & read response from service
            HttpWebResponse webresponse;
            Encoding enc;
            StreamReader responseStream;
            string strResult = string.Empty;
            try
            {
                webresponse = (HttpWebResponse)webrequest.GetResponse();
                enc = System.Text.Encoding.GetEncoding("utf-8");
                responseStream = new StreamReader(webresponse.GetResponseStream(), enc);
                strResult = responseStream.ReadToEnd();
                responseStream.Close();
                webresponse.Close();
            }
            catch (WebException we)
            {
                strResult = "A Web Exception has occurred\n\n" + we.Message;
            }

            return strResult;
        }

        /// <summary>
        /// Sends data to the service via the HTTP PUT. PUT must be idempotent.
        /// </summary>
        /// <param name="uriTemplate">The uri template for the desired method.</param>
        /// <param name="jsonData">The JSON object to send.</param>
        /// <returns></returns>
        private static string CallPutService(string uriTemplate, string jsonData)
        {
            string url = ServiceAddress + uriTemplate;
            byte[] buffer = Encoding.UTF8.GetBytes(jsonData);
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
            request.Method = "PUT";
            request.Credentials = new NetworkCredential(username, password);
            request.ContentType = "application/x-www-form-urlencoded";

            // set up certificate trust
            ServicePointManager.ServerCertificateValidationCallback =
            new RemoteCertificateValidationCallback(
            delegate(object sender2, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
            {
                return true;
            });
            using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
            {
                sw.Write(jsonData);
                Console.WriteLine(jsonData);
                sw.Close();
            }
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            using (StreamReader sr = new StreamReader(response.GetResponseStream()))
            {
                string res = sr.ReadToEnd();
                return res;
            }
        }

        /// <summary>
        /// Sends data to the service via the HTTP POST. POST is not guaranteed idempotent.
        /// </summary>
        /// <param name="uriTemplate">The uri template for the desired method.</param>
        /// <param name="jsonData">The JSON object to send.</param>
        /// <returns></returns>
        private static string CallPostService(string uriTemplate, string jsonData)
        {
            HttpWebResponse response = null;
            try
            {
                string url = ServiceAddress + uriTemplate;
                byte[] buffer = Encoding.UTF8.GetBytes(jsonData);
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
                request.Method = "POST";
                request.Credentials = new NetworkCredential(username, password);
                request.ContentType = "application/x-www-form-urlencoded";
                //request.Timeout = 10000;

                // set up certificate trust
                ServicePointManager.ServerCertificateValidationCallback =
                new RemoteCertificateValidationCallback(
                delegate(object sender2, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
                {
                    return true;
                });
                using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
                {
                    sw.Write(jsonData);
                    Console.WriteLine(jsonData);
                    sw.Close();
                }
                        
                response = (HttpWebResponse)request.GetResponse();
            }
            catch (WebException e)
            {
                if (e.Status == WebExceptionStatus.Timeout) MessageBox.Show("The request timed out. If this problem persists, please contact your system administrator");
                else MessageBox.Show(e.ToString() + "\n\nAn error occured when sending the request to the server.\n\nError Code: " + e.Status);
                return null;
            }
            using (StreamReader sr = new StreamReader(response.GetResponseStream()))
            {
                string res = sr.ReadToEnd();
                return res;
            }
        }

        #endregion
    }
}
